import uuid
from datetime import datetime

from sqlalchemy import or_
from flask import request
from flask_jwt_extended import \
    get_jwt_identity,\
    jwt_required,\
    create_access_token,\
    create_refresh_token

from .marshmallow import MobileSchema,ValidationError,UserSchema
from .models import User,db
from application import message,status
from application.utils.captcha import \
    check_captcha,\
    CaptchaError,\
    CaptchaParamsError,\
    CaptchaNetWorkError,\
    CaptchaFailError

def check_mobile(mobile):
    """验证手机号码是否已经注册"""
    ms = MobileSchema()
    try:
        ms.load({"mobile": mobile})
        ret = {"errno": status.CODE_OK, "errmsg": message.ok}
    except ValidationError as e:
        ret = {"errno": status.CODE_VALIDATE_ERROR, "errmsg": e.messages["mobile"][0]}

    return ret

def register(mobile,password,password2, sms_code):
    """用户基本信息注册"""
    # 1. 验证手机是否已经注册
    ret = check_mobile(mobile)
    if ret["errno"] != 1000:
        return ret

    # 2. 验证并保存用户信息
    try:
        us = UserSchema()
        instance = us.load({
                "mobile":mobile,
                "password":password,
                "password2":password2,
                "sms_code": sms_code
            })
        ret = {"errno": status.CODE_OK, "errmsg":message.ok,"data": us.dump(instance)}

    except ValidationError as e:
        if e.messages.get("sms_code"):
            errmsg = e.messages["sms_code"][0]
        elif e.messages.get("password"):
            errmsg = e.messages["password"][0]
        else:
            errmsg = "验证失败！"

        ret = {"errno": status.CODE_VALIDATE_ERROR, "errmsg": errmsg}

    # 4. 返回结果
    return ret

def login(account, password, ticket,randstr):
    """
    jwt登录
    :param account: 登录账户[手机号、邮箱、用户名]
    :param password: 登录密码
    :param ticket: 验证码验证成功以后回调的凭据
    :param randstr: 验证码验证成功以后回调的随机数
    :return: access_token登录令牌refresh_token登录凭据
    """
    # 0. 验证防水墙回调的凭据和随机数
    try:
        check_captcha(ticket,randstr,request.remote_addr)
    except CaptchaError:
        return {"errno": status.CODE_VALIDATE_ERROR, "errmsg": message.validate_fail}

    # 1. 通过数据库进行账号和密码的匹配
    if len(account)<1 or len(password) < 1:
        return {
            "errno":status.CODE_MISSING_PARAMS,
            "errmsg": message.no_account_or_password,
        }

    user = User.query.filter(or_(User.mobile == account, User.name == account, User.email==account)).first()
    if user is None:
        return {
            "error": status.CODE_NO_SUCH_USER,
            "errmsg": message.no_user
        }

    if not user.check_password(password):
        return {
            "error": status.CODE_VALIDATE_ERROR,
            "errmsg": message.password_is_error
        }

    # 数据库中用户信息更新
    user.updated_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    user.ip_address = request.remote_addr
    db.session.commit()

    user_data = {
        "id": user.id,
        "nickname": user.nickname if user.nickname else "",
        "age": user.age if user.age else 0,
        "money": float(user.money) if user.money else 0,
        "ip_address": user.ip_address,
        "intro": user.intro if user.intro else "",
        "avatar": user.avatar if user.avatar else "",
        "sex": True if user.sex else False,
        "unique_id": str(uuid.uuid4()),
        "province": user.province,
        "city": user.city,
        "area": user.area,
        "created_time": user.created_time.strftime("%Y-%m-%d %H:%M:%S") if user.created_time else "",
        "updated_time": user.updated_time.strftime("%Y-%m-%d %H:%M:%S") if user.updated_time else "",
    }

    # 2. 生成jwt assess token 和 refresh token
    access_token = create_access_token(identity=user_data) # identity 就是载荷
    refresh_token = create_refresh_token(identity=user_data)

    # 3. 返回2个token给客户端
    return {
        "errno":status.CODE_OK,
        "errmsg": message.ok,
        "access_token": access_token,
        "refresh_token": refresh_token
    }

@jwt_required() # 验证 jwt的 assess token
def info():
    """获取当前用户详细信息"""
    user_data = get_jwt_identity()
    user_info = {}
    return {
        "errno": status.CODE_OK,
        "errmsg": message.ok,
        "data": {
            **user_info,
            **user_data
        }
    }

@jwt_required(refresh=True) # 验证 jwt的 refresh token
def refresh():
    """依靠refresh token 换取 assess token"""
    identity = get_jwt_identity() # 获取refresh token中的载荷
    access_token = create_access_token(identity=identity)
    return {
        "errno": status.CODE_OK,
        "errmsg": message.ok,
        "access_token":access_token
    }
